package com.zwps.common.tool.tree;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;

public class TreeTool {

    /**
     * 数组转树结构
     * 
     * @Title: build
     * @Description:
     * @param <T>          需要转换的任意对象
     * @param <K>          树的ID和ParentId字段类型
     * @param <D>          原对象类型转换后的对象类型
     * @param <R>          转换后返回的树对象类型
     * @param list         需要转换的对象数组
     * @param treeInstance 创建返回的树对象或子类的匿名方法（添加这个是为了对返回的对象支持更好的扩展）
     * @param idFun        获取树ID的匿名方法
     * @param parentIdFun  获取树节点上级ID的匿名方法
     * @param nameFun      获取树节点名称的匿名方法
     * @param sortFun      获取树节点排序值的匿名方法
     * @return List<R> 返回的树结果数组
     * @author lyh
     * @date 2023年7月30日 下午12:30:12
     */
    public static <T, K, D, R extends Trees<K, D, R>> List<R> build(List<T> list, Function<T, R> treeInstance,
            Function<T, K> idFun, Function<T, K> parentIdFun, Function<T, String> nameFun,
            Function<T, Comparable<?>> sortFun) {
        return build(list, parentIdFun.apply(list.get(0)), treeInstance, idFun, parentIdFun, nameFun, sortFun);
    }

    public static <T, K, D, R extends Trees<K, D, R>> List<R> build(List<T> list, K parentId,
            Function<T, R> treeInstance, Function<T, K> idFun, Function<T, K> parentIdFun, Function<T, String> nameFun,
            Function<T, Comparable<?>> sortFun) {
        List<TreeNode<K>> nodeList = CollUtil.newArrayList();
        for (T t : list) {
            TreeNode<K> n = new TreeNode<K>();
            n.setId(idFun.apply(t));
            n.setName(nameFun.apply(t));
            n.setParentId(parentIdFun.apply(t));
            n.setWeight(sortFun.apply(t));
            HashMap<String, Object> map = new HashMap<String, Object>();
            map.put("data", t);
            n.setExtra(map);
            nodeList.add(n);
        }
        return build(nodeList, parentId, treeInstance);
    }

    private static <T, K, D, R extends Trees<K, D, R>> List<R> build(List<TreeNode<K>> list, K parentId,
            Function<T, R> treeInstance) {
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setWeightKey("sort");
        List<Tree<K>> treeList = TreeUtil.build(list, parentId, treeNodeConfig, (treeNode, tree) -> {
            tree.setId(treeNode.getId());
            tree.setWeight(treeNode.getWeight());
            tree.setParentId(treeNode.getParentId());
            tree.setName(treeNode.getName());
            tree.putAll(treeNode.getExtra());
        });
        return toTrees(treeList, treeInstance);
    }

    private static <T, K, D, R extends Trees<K, D, R>> List<R> toTrees(List<Tree<K>> treeList,
            Function<T, R> treeInstance) {
        if (treeList == null) {
            return null;
        }

        List<R> list = new ArrayList<>(treeList.size());
        for (Tree<K> tree : treeList) {
            list.add(newTrees(tree, treeInstance));
        }

        return list;
    }

    @SuppressWarnings("unchecked")
    private static <T, K, D, R extends Trees<K, D, R>> R newTrees(Tree<K> tree, Function<T, R> treeInstance) {
        if (tree == null) {
            return null;
        }
        T data = (T) tree.get("data");
        Trees<K, D, R> trees = treeInstance.apply(data);
        trees.setChildren(toTrees(tree.getChildren(), treeInstance));
        trees.setId(tree.getId());
        trees.setName((String) tree.getName());
        trees.setParentId(tree.getParentId());
        trees.setSort((Integer) tree.getWeight());
        // 是否需要返回由treeInstance.apply(data);中处理是否需要
//        trees.setData((D) tree.get("data"));
        return (R) trees;
    }
}
